/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu>
 * <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_STRING_H
#define SX_STRING_H

/*
 * The String class contains a dependency to the ArrayList class due to the
 * various character sequences that a string can be represented as. This is
 * due to the Unicode support of the String class.
 */
#include <sxArrayList.h>

namespace Sx {

/*
 * Opaque pointer foreward declaration. This type defines the implementation
 * struct used to hold the implementation details of the String class. None
 * of the internal structure in this struc should be exposed to the actual
 * interface of the String class. The Detail namespace contains framework
 * specific types that should not be used in client code.
 */
namespace Detail {
struct StringImplementation;
}

/*
 * The Sx implementation of a string provides an extremely user friendly
 * interface while also providing basic support for all Unicode standards.
 * The development of this class was based on the simplicity of the interface
 * and an object oriented approach that does not rely on iterators.
 * C++ purests be forewarned; you will not appreciate this design, but having
 * these functions easily avaliable will decrease prototype completion time.
 */
class String {
public:
	String();
	String(const String& string);
	String(const std::string& string);
	String(char c);
	String(const char* s);

	String(const char32_t* s);
	String(short value);
	String(int value);
	String(long value);
	String(float value);
	String(double value);
	~String();

	/*
	 * The append functions allow different types of data to be appended to
	 * a String. If the data type is numerical, then the string representation
	 * of that data will be appended to the String.
	 */
	void append(char c);
	void append(const String& string);
	void append(const std::string& string);
	void append(const char* s);
	void append(short value);
	void append(int value);
	void append(long value);
	void append(float value);
	void append(double value);

	/*
	 * The push_back functions allow different types of data to be appended to
	 * a String. If the data type is numerical, then the string representation
	 * of that data will be appended to the String.
	 */
	void push_back(char c);
	void push_back(const String& string);
	void push_back(const char* s);
	void push_back(short value);
	void push_back(int value);
	void push_back(long value);
	void push_back(float value);
	void push_back(double value);
	void push_front(char c);
	void push_front(const String& string);
	void push_front(const char* s);
	void push_front(short value);
	void push_front(int value);
	void push_front(long value);
	void push_front(float value);
	void push_front(double value);

	/*
	 * Compares the contentes of this String to the contents of another
	 * Strings contents.
	 */
	int compare(const String& string, bool caseSensitive = false) const;

	/*
	 * Clears this String to be an empty string.
	 */
	void clear();

	/*
	 * Removes all whitespace from the beginning and end (head,tail) of this
	 * String.
	 */
	void trim();


	/*
	 * Parses the characters of this String to determine if this String holds
	 * a textual representation of an integer value. If this String contains
	 * a textual representation of an integer value then the function will
	 * return true; otherwise it will return false.
	 */
	bool isInt() const;

	/*
	 * Parses the characters of this String to determine if this String holds
	 * a textual representation of an double value. If this String contains
	 * a textual representation of an double value then the function will
	 * return true; otherwise it will return false.
	 */
	bool isDouble() const;

	/*
	 * Parses the characters of this String to determine if this String holds
	 * a textual representation of an double value. If this String contains
	 * a textual representation of an double value then the function will
	 * return true; otherwise it will return false.
	 */
	bool isFloat() const;

	/*
	 * Determines if this String contains no characters. If this String
	 * contains no characters then this function will return true; Otherwise
	 * this function will return false.
	 */
	bool isEmpty() const;
	void insert(unsigned int index, char c);

	/*
	 * Returns the number of characters contained in this String.
	 */
	unsigned int length() const;

	/*
	 * Finds the index of the character in this String. If the character is
	 * found in this String its index is returned; otherwise this function
	 * returns -1 if c is not found.
	 */
	int findFirstInstanceOf(char c) const;

	/*
	 * This function erases a substring section of this String.
	 * start specifies the starting index to be removed and end
	 * specifies the end index to be removed (both are inclusive).
	 */
	bool eraseSubstring(unsigned int start, unsigned int end);

	/*
	 * Returns a character in this String at index. (Technically limited to
	 * retrieving the first (2^32)-1 characters of this String.
	 */
	char get(unsigned int index) const;
	char at(unsigned int index) const;
	char getUTF8(unsigned int index) const;
	char atUTF8(unsigned int index) const;
	char16_t getUTF16(unsigned int index) const;
	char16_t atUTF16(unsigned int index) const;
	char32_t getUTF32(unsigned int index) const;
	char32_t atUTF32(unsigned int index) const;

	/*
	 * Removes all instances of the provided char from this String.
	 */
	void remove(char c, bool caseSensitive = false);

	/*
	 * Returns a String that contains the content sequence of this String but
	 * each character is represented by its lower-case form.
	 */
	String toLower() const;

	/*
	 * Returns a String that contains the content sequence of this String but
	 * each character is represented by its upper-case form.
	 */
	String toUpper() const;

	/*
	 * Returns the content of this String with all whitespace characters removed
	 * from the front and back (head,tail).
	 */
	String trimmed() const;

	/*
	 * Return a String contained in this string starting at start and ending
	 * at end. Start represents the index of the first character in the new 
	 * string and end represents the index of the last character.
	 */
	String substring(unsigned int start, unsigned int end) const;

	/*
	 * Allows this String to be used as a standard string. (Standard reguarding
	 * Unicode support may change).
	 */
	operator std::string ();

	/*
	 * Conversion to each type of string encoding is supported through the use
	 * of character arrays. Arrays can also be used directly as native pointers.
	 * This specific interface is defined to ensure that the returned character
	 * sequence lifetime is not tied to the String object from which it was
	 * retrieved. Design intent: Limit hanging pointer risk.
	 */
	Util::ArrayList<char> toAscii(bool null = true) const;
	Util::ArrayList<char> toUTF8(bool null = true) const;
	Util::ArrayList<char16_t> toUTF16(bool null = true) const;
	Util::ArrayList<char32_t> toUTF32(bool null = true) const;

	/*
	 * Allows for the direct assignment of a string literal to a String.
	 */
	String& operator = (const char* s);

	/*
	 * Performs a normal assignment of a String object. The lhs will receive
	 * a copy of the characters contained by the rhs.
	 */
	String& operator = (const String& string);

	/*
	 * Append operations are provided as native operations in addition to the
	 * basic append functions. If the provided datatype is numerical the
	 * string representation of that value will be appended to the String.
	 */
	String& operator += (char c);
	String& operator += (const String& string);
	String& operator += (short value);
	String& operator += (int value);
	String& operator += (long value);
	String& operator += (float value);
	String& operator += (double value);
	String operator + (const String& string);

	bool operator < (const String& string) const;
	bool operator > (const String& string) const;
	bool operator <= (const String& string) const;
	bool operator >= (const String& string) const;

	/*
	 * Provides a global String operation for the + operator:
	 * String s = "Literal" + SxString;
	 */
	friend String operator + (const char* literal, const String& string);

	/*
	 * ASCII represnetation is assumed for the basic subscript operator.
	 */
	char operator [] (unsigned int index);
	char operator [] (unsigned int index) const;

	bool operator == (const String& string);
	bool operator == (const String& string) const;
	bool operator != (const String& string);

	static String Trim(const String& string);

	/*
	 * Returns an all lower-case version of the provided String.
	 */
	static String ToLower(const String& string);

	/*
	 * Returns an all upper-case versioon of the provided string.
	 */
	static String ToUpper(const String& string);

	/*
	 * Returns the number of occurances of the character c in this
	 * String.
	 */
	static unsigned int Occurances(const String& string, char c);

	/*
	 * Each of the ValueOf functions provide a String representation of the 
	 * provided value.
	 */
	static String ValueOf(short value);
	static String ValueOf(int value);
	static String ValueOf(long value);
	static String ValueOf(float value);
	static String ValueOf(double value);

	/*
	 * These functions return the hex values of the decimal values provided.
	 */
	static String HexValueOf(int value, bool upper = true);
	static String HexValueOf(long value, bool upper = true);

	/*
	 * Utilize basic ASCII output for basic stream outputs.
	 */
	friend std::ostream& operator << (std::ostream& out, const String& string) {
		out << string.toAscii(false);
		return out;
	}

	/*
	 * Utilize basic ASCII output for basic stream outputs.
	 */
	friend std::ostream& operator << (std::ostream& out, const String* string) {
		if ( string == nullptr ) return out;
		out << string->toAscii(false);
		return out;
	}

	friend String operator + (const char* cString, const String& string) {
		String s(cString);
		s += string;
		return s;
	}

	/*
	 * This constant is used to represent any invalid index of a String.
	 */
	static const int INVALID_STRING_POSITION = -1;

private:
	/*
	 * Provides a an opaque pointer to the implementation of this String class.
	 * The String type used in the definition of this object does not matter as
	 * long as it implements the defined interface of this class. The string
	 * implementation structure is hidden in the Detail namespace so that it
	 * will not be used in client code.
	 */
	Detail::StringImplementation* imp;

};

/*
 * String hash function.
 */
struct StringHash {
	unsigned int operator() (const String& string) const;
};

/*
 * String equality function.
 */
struct StringEq {
	bool operator() (const String& a, const String& b) const;
};

}

#endif
